#!/usr/bin/env node

/**
 * 数据库备份和恢复工具
 * 支持MySQL和SQLite数据库的备份、恢复和清理操作
 */

const fs = require('fs');
const path = require('path');
const { exec } = require('child_process');
const { promisify } = require('util');
const execAsync = promisify(exec);

// 加载环境配置
require('dotenv').config();

class DatabaseBackup {
  constructor() {
    this.backupDir = path.join(__dirname, 'backups');
    this.dbType = process.env.DB_TYPE || 'mysql';
    this.maxBackups = parseInt(process.env.MAX_BACKUPS) || 10;
    
    // 确保备份目录存在
    if (!fs.existsSync(this.backupDir)) {
      fs.mkdirSync(this.backupDir, { recursive: true });
    }
  }

  generateBackupFilename(prefix = 'backup') {
    const timestamp = new Date().toISOString()
      .replace(/[-:T]/g, '')
      .split('.')[0];
    const extension = this.dbType === 'sqlite' ? 'db' : 'sql';
    return `${prefix}_${timestamp}.${extension}`;
  }

  async createMySQLBackup(filename) {
    const backupPath = path.join(this.backupDir, filename);
    
    const command = [
      'mysqldump',
      `--host=${process.env.DB_HOST}`,
      `--port=${process.env.DB_PORT}`,
      `--user=${process.env.DB_USER}`,
      `--password=${process.env.DB_PASSWORD}`,
      '--single-transaction',
      '--routines',
      '--triggers',
      '--add-drop-table',
      '--extended-insert',
      '--create-options',
      process.env.DB_NAME,
      `> ${backupPath}`
    ].join(' ');

    console.log(`Creating MySQL backup: ${filename}`);
    await execAsync(command);
    
    // 验证备份文件
    const stats = fs.statSync(backupPath);
    if (stats.size === 0) {
      throw new Error('Backup file is empty');
    }

    return {
      filename,
      path: backupPath,
      size: stats.size,
      created: new Date()
    };
  }

  async createSQLiteBackup(filename) {
    const sourcePath = process.env.DB_PATH || './database/local.db';
    const backupPath = path.join(this.backupDir, filename);
    
    if (!fs.existsSync(sourcePath)) {
      throw new Error(`SQLite database not found: ${sourcePath}`);
    }

    console.log(`Creating SQLite backup: ${filename}`);
    
    // 使用SQLite的.backup命令创建备份
    const command = `sqlite3 ${sourcePath} ".backup ${backupPath}"`;
    await execAsync(command);
    
    // 验证备份文件
    const stats = fs.statSync(backupPath);
    if (stats.size === 0) {
      throw new Error('Backup file is empty');
    }

    return {
      filename,
      path: backupPath,
      size: stats.size,
      created: new Date()
    };
  }

  async backup(customName = null) {
    const filename = customName || this.generateBackupFilename();
    
    try {
      let result;
      
      if (this.dbType === 'sqlite') {
        result = await this.createSQLiteBackup(filename);
      } else {
        result = await this.createMySQLBackup(filename);
      }

      console.log(`✅ Backup created successfully:`);
      console.log(`   File: ${result.filename}`);
      console.log(`   Size: ${(result.size / 1024).toFixed(2)} KB`);
      console.log(`   Path: ${result.path}`);

      // 清理旧备份
      await this.cleanupOldBackups();
      
      return result;
    } catch (error) {
      console.error(`❌ Backup failed: ${error.message}`);
      throw error;
    }
  }

  async restoreMySQLBackup(backupFile) {
    const backupPath = path.join(this.backupDir, backupFile);
    
    if (!fs.existsSync(backupPath)) {
      throw new Error(`Backup file not found: ${backupFile}`);
    }

    console.log(`Restoring MySQL backup: ${backupFile}`);
    
    const command = [
      'mysql',
      `--host=${process.env.DB_HOST}`,
      `--port=${process.env.DB_PORT}`,
      `--user=${process.env.DB_USER}`,
      `--password=${process.env.DB_PASSWORD}`,
      process.env.DB_NAME,
      `< ${backupPath}`
    ].join(' ');

    await execAsync(command);
  }

  async restoreSQLiteBackup(backupFile) {
    const backupPath = path.join(this.backupDir, backupFile);
    const targetPath = process.env.DB_PATH || './database/local.db';
    
    if (!fs.existsSync(backupPath)) {
      throw new Error(`Backup file not found: ${backupFile}`);
    }

    console.log(`Restoring SQLite backup: ${backupFile}`);
    
    // 创建当前数据库的备份
    if (fs.existsSync(targetPath)) {
      const preRestoreBackup = this.generateBackupFilename('pre_restore');
      fs.copyFileSync(targetPath, path.join(this.backupDir, preRestoreBackup));
      console.log(`Created pre-restore backup: ${preRestoreBackup}`);
    }
    
    // 恢复备份
    fs.copyFileSync(backupPath, targetPath);
  }

  async restore(backupFile) {
    try {
      if (this.dbType === 'sqlite') {
        await this.restoreSQLiteBackup(backupFile);
      } else {
        await this.restoreMySQLBackup(backupFile);
      }

      console.log(`✅ Database restored successfully from: ${backupFile}`);
    } catch (error) {
      console.error(`❌ Restore failed: ${error.message}`);
      throw error;
    }
  }

  listBackups() {
    const files = fs.readdirSync(this.backupDir)
      .filter(file => {
        const ext = path.extname(file).toLowerCase();
        return (this.dbType === 'sqlite' && ext === '.db') || 
               (this.dbType === 'mysql' && ext === '.sql');
      })
      .map(file => {
        const filePath = path.join(this.backupDir, file);
        const stats = fs.statSync(filePath);
        return {
          filename: file,
          size: stats.size,
          created: stats.mtime,
          path: filePath
        };
      })
      .sort((a, b) => b.created - a.created);

    console.log('\n📁 Available Backups:');
    console.log('=====================');
    
    if (files.length === 0) {
      console.log('No backup files found');
      return files;
    }

    files.forEach((file, index) => {
      const sizeKB = (file.size / 1024).toFixed(2);
      const date = file.created.toLocaleString();
      console.log(`${index + 1}. ${file.filename}`);
      console.log(`   Size: ${sizeKB} KB`);
      console.log(`   Created: ${date}`);
      console.log('');
    });

    return files;
  }

  async cleanupOldBackups() {
    const backups = this.listBackups();
    
    if (backups.length <= this.maxBackups) {
      return;
    }

    const toDelete = backups.slice(this.maxBackups);
    
    console.log(`\n🧹 Cleaning up ${toDelete.length} old backups...`);
    
    for (const backup of toDelete) {
      try {
        fs.unlinkSync(backup.path);
        console.log(`   Deleted: ${backup.filename}`);
      } catch (error) {
        console.error(`   Failed to delete ${backup.filename}: ${error.message}`);
      }
    }
  }

  async autoBackup() {
    const filename = this.generateBackupFilename('auto');
    return await this.backup(filename);
  }

  async preDeploymentBackup() {
    const filename = this.generateBackupFilename('pre_deployment');
    return await this.backup(filename);
  }

  async preMigrationBackup() {
    const filename = this.generateBackupFilename('pre_migration');
    return await this.backup(filename);
  }
}

// CLI 接口
async function main() {
  const command = process.argv[2];
  const arg = process.argv[3];

  const backup = new DatabaseBackup();

  try {
    switch (command) {
      case 'create':
        await backup.backup(arg);
        break;
      case 'restore':
        if (!arg) {
          console.error('Please specify a backup file to restore');
          process.exit(1);
        }
        await backup.restore(arg);
        break;
      case 'list':
        backup.listBackups();
        break;
      case 'cleanup':
        await backup.cleanupOldBackups();
        break;
      case 'auto':
        await backup.autoBackup();
        break;
      case 'pre-deploy':
        await backup.preDeploymentBackup();
        break;
      case 'pre-migrate':
        await backup.preMigrationBackup();
        break;
      default:
        console.log('Database Backup Tool');
        console.log('===================');
        console.log('Usage:');
        console.log('  node backup.js create [name]     - Create a new backup');
        console.log('  node backup.js restore <file>    - Restore from backup');
        console.log('  node backup.js list              - List all backups');
        console.log('  node backup.js cleanup           - Remove old backups');
        console.log('  node backup.js auto              - Create automatic backup');
        console.log('  node backup.js pre-deploy        - Create pre-deployment backup');
        console.log('  node backup.js pre-migrate       - Create pre-migration backup');
        break;
    }
  } catch (error) {
    console.error('Operation failed:', error.message);
    process.exit(1);
  }
}

if (require.main === module) {
  main();
}

module.exports = DatabaseBackup;